package pt.xpand.xinx.entities;

import java.util.Date;
import java.util.Random;

import pt.xpand.xinx.entities.interfaces.IPlayer;
import pt.xpand.xinx.utils.Constants;

/**
 * @author Kiko
 * 
 *         Game controller. Controls the main flow of the game.
 * 
 */
public class Game {

	private IPlayer red, blue;
	private Board board;
	private int turnLimit, boardSize, boardDimension;

	/**
	 * Constructor for Game.java
	 * 
	 * @param red
	 * @param blue
	 * @param turnLimit
	 * @param boardSize
	 * @param boardDimension
	 */
	public Game(IPlayer red, IPlayer blue, int turnLimit, int boardSize,
			int boardDimension) {
		this.red = red;
		this.blue = blue;
		this.turnLimit = turnLimit;
		this.boardDimension = boardDimension;
		this.boardSize = boardSize;
	}

	/**
	 * Returns the Red Player implementation
	 * 
	 * @return IPlayer
	 */
	public IPlayer getRed() {
		return red;
	}

	/**
	 * Returns the Blue Player implementation
	 * 
	 * @return IPlayer
	 */
	public IPlayer getBlue() {
		return blue;
	}

	/**
	 * Returns the time limit defined for each turn
	 * 
	 * @return int
	 */
	public int getTurnLimit() {
		return turnLimit;
	}

	/**
	 * Returns the board size. A size of X represents a board with dimensions
	 * X*X
	 * 
	 * @return int
	 */
	public int getBoardSize() {
		return boardSize;
	}

	/**
	 * Return the number of dimensions of the board. The number of floors of
	 * dimensions X*X
	 * 
	 * @return int
	 */
	public int getBoardDimension() {
		return boardDimension;
	}

	/**
	 * Starts the game flow, until we have a winner or reach a tie and return
	 * NULL
	 * 
	 * @return IPlayer
	 */
	public IPlayer start() {
		IPlayer winner = null;

		IPlayer first = null;
		IPlayer last = null;

		// Prints the game info
		printGameStartInfo();

		first = coinToss();
		System.out.println("The winner of the coin toss is " + first.getName());
		if (first.getName().equals(blue.getName())) {
			last = red;
		} else {
			last = blue;
		}
		
		String symbol1 = first.getSymbol();
		String symbol2 = last.getSymbol();
		
		if(symbol1.equals(symbol2)) {
			System.out.println("Players have equal symbols. Changing to defauld..");
			symbol1 = Constants.PLAYER_1_DEFAULT;
			symbol2 = Constants.PLAYER_2_DEFAULT;
		} 
		
		System.out.println("The first to go is " + first.getName()+" with symbol "+symbol1);
		System.out.println("The second to go is " + last.getName()+" with symbol "+symbol2);

		// Creates board
		board = new Board(boardSize, boardDimension);
		board.showBoard();

		Position pos = null;
		long turnStart = 0;
		long turnEnd = 0;
		
		long totalTurn1 = 0;
		long totalTurn2 = 0;
		
		while (true) {
			//First Player Cycle
			System.out.println(first.getName()+" turn...");
			turnStart = new Date().getTime();
			pos = first.play(board);
			System.out.println(first.getName()+" chooses ("+pos.getX()+","+pos.getY()+")");
			turnEnd = new Date().getTime();
			totalTurn1 += (turnEnd - turnStart);
			if ((turnEnd - turnStart) <= turnLimit) {
				if (board.placePiece(pos, symbol1)) {
					System.out.println(first.getName()
							+ ": Turn ended. Turn time:"
							+ (turnEnd - turnStart) / 1000);
				} else {
					System.out.println("GameMaster: Invalid position. "
							+ first.getName() + " lost its turn.");
				}
			} else {
				System.out.println("GameMaster: Time exceeded. "
						+ first.getName() + " lost its turn.");
			}
			board.showBoard();
			if(checkWinner(first.getSymbol())) {
				winner = first;
				break;
			} 
			if(board.isFull()) {
				break;
			}
			//Second Player Cycle
			System.out.println(last.getName()+" turn...");
			turnStart = new Date().getTime();
			pos = last.play(board);
			System.out.println(last.getName()+" chooses ("+pos.getX()+","+pos.getY()+")");
			turnEnd = new Date().getTime();
			totalTurn2 += (turnEnd - turnStart);
			if ((turnEnd - turnStart) <= turnLimit) {
				if (board.placePiece(pos, symbol2)) {
					board.showBoard();
					System.out.println(last.getName()
							+ ": Turn ended. Turn time:"
							+ (turnEnd - turnStart) / 1000);
				} else {
					System.out.println("GameMaster: Invalid position. "
							+ last.getName() + " lost its turn.");
				}
			} else {
				System.out.println("GameMaster: Time exceeded. "
						+ last.getName() + " lost its turn.");
			}
			if(checkWinner(last.getSymbol())) {
				winner = last;
				break;
			}
			if(board.isFull()) {
				break;
			}
		}

		if (winner != null) {
			System.out.println("GameMaster: Game ended. The winner is "
				+ winner.getName());
		} else {
			System.out.println("GameMaster: The game is a tie.");
			System.out.println("GameMaster: Winner decided by turn total time. If equal, the winner of the coin toss wins the game.");
			System.out.println("GameMaster: "+first.getName()+" wasted "+totalTurn1+"ms");
			System.out.println("GameMaster: "+last.getName()+" wasted "+totalTurn2+"ms");
			if(totalTurn1 <= totalTurn2) {
				winner = first;
			} else {
				winner = last;
			}
			System.out.println("GameMaster: The winner by decision is "+winner.getName());
		}
		return winner;
	}

	/**
	 * Checks if there is a winner
	 * 
	 * @return IPlayer
	 */
	private boolean checkWinner(String symbol) {
		return board.checkWinner(symbol);
	}

	/**
	 * Prints the info for the game starting
	 */
	private void printGameStartInfo() {
		System.out.println("");
		System.out
				.println("####################################################################");
		System.out
				.println("##                                                                ##");
		System.out.println("##        " + red.getName()
				+ "          VS.         " + blue.getName()
				+ "                    ##");
		System.out
				.println("##                                                                ##");
		System.out.println("##                  Board Size:" + boardSize + "x"
				+ boardSize + "                                ##");
		System.out.println("##                  Board Dimensions:"
				+ boardDimension + "                            ##");
		System.out.println("##                  Turn Time Limit:" + turnLimit
				+ "                            ##");
		System.out
				.println("##                                                                ##");
		System.out
				.println("####################################################################");
		System.out.println("");
	}

	/**
	 * Simulates the coin toss. Decides who goes first
	 * 
	 * @return IPlayer
	 */
	private IPlayer coinToss() {
		Random coin = new Random();
		int result = coin.nextInt(10) + 1;

		if (result < 6) {
			return blue;
		} else {
			return red;
		}

	}

}
